home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS09.ADF / MyCLI / MyCLI.c < prev    next >
C/C++ Source or Header  |  1986-05-22  |  55KB  |  2,081 lines

  1. /*
  2. Original usenet posting header:
  3.  
  4. From: uwvax!3comvax!mykes (Mike Schwartz)
  5. Newsgroups: net.micro.amiga
  6. Subject: MyCLI - CLI/Terminal program
  7. Date: 31 Dec 85 09:15:18 GMT
  8. Organization: 3Com Corp; Mountain View, CA
  9.  
  10.  * MyCLI - a replacement for the standard AmigaDos CLI
  11.  * Programmed by Mike Schwartz (C)1985 MS Software, All Rights Reserved!
  12.  * Feel free to give this software away, in any form, for no charge only.
  13. */
  14.  
  15. /*
  16.                   the original version 1.0 was by Mike Schwartz
  17.  
  18.                   all of RTW (Rick Wirch's) revisions make up version 1.01
  19.                   these include:
  20.                   o all of command line editing capabilities [getcommand()]
  21.                   o 'history' ability with up and down keys
  22.                   o refinement and cleanup of window opening at startup
  23.                   o corrections in executive() function
  24.                   o limited redirection capabilities
  25.                   o increase in capabilities of prompt printer
  26.                   o copy's ability to understand directories and only one
  27.                     parameter to copy into current directory
  28.                   o copy's ability to understand '*' as console device
  29.                   o recursive directory ability using "-r" or "opt a"
  30.                   o addition of 'list' like command
  31.                   o 'more' command to view a file a page at a time
  32.                   o marked increase in the speed of 'type' by buffering
  33.                   o multiple refinements in code.
  34.  
  35.  
  36.    3/28/86  Djj   all of Djj revisions make up version 1.02
  37.    3/28/86  Djj   Converted source to compile with Aztec C compiler.
  38.                   Added array of pointers *args[] to simulate *argv[]
  39.                   Manx doesn't allocate any more pointers than what are
  40.                   on the command line.  The scheme used here requires at
  41.                   5 pointers be allocated on entry.
  42.                   Added Directories count to list command.  Also added
  43.                   1 block, 512 bytes to totals for each directory.
  44.  
  45.                   MANX compiler objects to char pointers initialized with
  46.                   a quoted string.  It generates correct code (mostly) but
  47.                   bores me with WARNING messages.  To eliminate this problem:
  48.  
  49.                      compile with:  cc -aso ram:mycli.asm
  50.                      assemble with: as -s1900 -o mycli.o ram:mycli.asm
  51.                      link with:     ln -o mycli mycli.o -lc
  52.  
  53.    3/31/86  Djj   Fixed date problem.
  54.    4/01/86  Djj   Added Phase of the Moon to date.  Changed serial driver
  55.                   to handle XON/XOFF.
  56.    4/02/86  Djj   Fixed my date problem.  date would crash when #of days was
  57.                   negative (somewhere around the year 2045 )
  58.  
  59.    4/21/86  RTW   fixed two bugs in the 'cd' command
  60.    thru              leading slashes now move up the tree one lvl per slash
  61.    5/07/86           using just slashes now removes trailing slash
  62.                   fixed several bugs in the 'copy' command
  63.                      copying '*' to a file now works correctly
  64.                      copying to a directory works for ALL cases
  65.                      having a complex path for the both files now works
  66.                      better error checking all around
  67.                   fixed bug in the 'define' command with FreeMem
  68.                   fixed bug in 'type' with the last line typed
  69.                   more command with redirection does not require input
  70.                   redirection can now be anywhere in the command
  71.                   added redirection capabilities to all commands
  72.                   added command path search
  73.                   added command chaining ability
  74.                   added new command 'set'
  75.                   added power up copying of 'run' to ram:
  76.                   reformatted and generally made code more readable
  77.                   put better error checking for weird cases in commands
  78.                   added some comments and changed version number to 2.00
  79. */
  80.  
  81. /* Remove the next line if not using the Aztec C compiler */
  82. #define  AZTEC 1        /* defined if using Aztec C compiler */
  83.  
  84. /* #define  MODEM */    /* to include simple terminal capabilities */
  85. #define  MOON           /* output phase of moon with date */
  86.  
  87. #ifdef   AZTEC
  88. #define  stpchr(s,c)  index(s,c)
  89. #define  ABS(val) (((val) < 0) ? (-(val)) : (val))
  90. #else
  91. extern UBYTE *stpchr();
  92. #endif
  93.  
  94. #include "exec/types.h"
  95. #include "exec/exec.h"
  96. #include "libraries/dos.h"
  97. #include "libraries/dosextens.h"
  98.  
  99. #ifdef MODEM
  100. #include "devices/serial.h"
  101. #endif
  102.  
  103. #ifdef   MOON
  104. extern UBYTE *moon();
  105. #endif
  106.  
  107. #define  ESC   0x1b
  108. #define  BRK   0x3
  109. #define  WriteWork() Write(mycli_outfp, work, (long)strlen(work))
  110.  
  111. #ifdef   TRUE
  112. #undef   TRUE        /* MANX defines these in an unusual way */
  113. #undef   FALSE
  114. #endif
  115.  
  116. #define  TRUE  1
  117. #define  FALSE 0
  118.  
  119. /*
  120.  * External function references
  121.  */
  122. extern   struct   MsgPort     *CreatePort();
  123. extern   struct   FileLock    *CreateDir();
  124. extern   struct   FileLock    *CurrentDir();
  125. extern   struct   FileLock    *Lock();
  126. extern   struct   FileHandle  *Open();
  127. extern   LONG     Seek(), Read(), Write(), ExNext();
  128. extern   VOID     Close(), FreeMem(), DateStamp(), UnLock();
  129. extern   UBYTE    *stpblk(), *AllocMem();
  130.  
  131. /*
  132.  * Forward function references
  133.  */
  134. VOID  capture(), cd(), copy(), date(), define_function_key(), delete(),
  135.       dir(), delete(), endcli(), help(), list(), ls(), md(), more(),
  136.       newcli(), offline(), rename(), set(), setcomment(),
  137.       TerminalMode(), time(), type(), whatis();
  138.  
  139. VOID  batchfile(), CommandInterpreter(), doserr(), executive(),
  140.       getcommand(), makename(), showprompt();
  141.  
  142. /*
  143.  * Tables
  144.  */
  145. struct {
  146.    UBYTE  *cmdname;
  147.    VOID   (*cmdfunc)();
  148.    } command_table[] = {
  149. #ifdef MODEM
  150.    (UBYTE *)"capture", &capture,
  151. #endif
  152.    (UBYTE *)"cd", &cd,
  153.    (UBYTE *)"copy", ©,
  154.    (UBYTE *)"date", &date,
  155.    (UBYTE *)"define", &define_function_key,
  156.    (UBYTE *)"def", &define_function_key,
  157.    (UBYTE *)"delete", &delete,
  158.    (UBYTE *)"del", &delete,
  159.    (UBYTE *)"dir", &dir,
  160.    (UBYTE *)"endcli", &endcli,
  161.    (UBYTE *)"help", &help,
  162.    (UBYTE *)"ls", &dir,
  163.    (UBYTE *)"list", &list,
  164.    (UBYTE *)"makedir", &md,
  165.    (UBYTE *)"md", &md,
  166.    (UBYTE *)"more", &more,
  167.    (UBYTE *)"mv", &rename,
  168.    (UBYTE *)"newcli", &newcli,
  169. #ifdef MODEM
  170.    (UBYTE *)"online", &TerminalMode,
  171.    (UBYTE *)"offline", &offline,
  172. #endif
  173.    (UBYTE *)"rename", &rename,
  174.    (UBYTE *)"setcomment", &setcomment,
  175.    (UBYTE *)"set", &set,
  176. #ifdef MODEM
  177.    (UBYTE *)"terminal", &TerminalMode,
  178. #endif
  179.    (UBYTE *)"time", &time,
  180.    (UBYTE *)"type", &type,
  181.    (UBYTE *)"whatis", &whatis,
  182.    NULL, NULL
  183.    };
  184.  
  185. UBYTE  *help_messages[] = {
  186. #ifdef MODEM
  187.    "capture    = capture file from modem",
  188. #endif
  189.    "cd         = change directory",
  190.    "copy       = copy from one file to another",
  191.    "date       = show current date",
  192.    "def        = define a function key (def f1 dir)",
  193.    "define     = \" \" (define f1 dir)",
  194.    "del        = delete file or subdirectory",
  195.    "delete     = \" \"",
  196.    "dir        = like AmigaDOS 'dir'",
  197.    "endcli     = exit to previous cli",
  198.    "help       = print this list",
  199.    "list       = like AmigaDOS 'list'",
  200.    "ls         = like AmigaDOS 'dir'",
  201.    "makedir    = make a new subdirectory",
  202.    "md         = \" \"",
  203.    "more       = view a file a page at a time",
  204.    "mv         = rename a file or directory",
  205.    "newcli     = birth another mycli task",
  206. #ifdef MODEM
  207.    "online     = enter or re-enter dumb terminal mode",
  208.    "offline    = terminate communication",
  209. #endif
  210.    "set        = set system variables like 'path', 'prompt', or 'chain'",
  211.    "rename     = rename a file or directory",
  212.    "setcomment = tag a file with a comment string",
  213. #ifdef MODEM
  214.    "terminal   = enter or re-enter dumb terminal mode",
  215. #endif
  216.    "time       = show current time",
  217.    "type       = view a file",
  218.    "whatis     = converts AmigaDos error codes to text",
  219.    0
  220. };
  221.  
  222. UBYTE  *function_key_definitions[20] = {
  223.    0,0,0,0,0,0,0,0,0,0,
  224.    0,0,0,0,0,0,0,0,0,0
  225.    };
  226.  
  227. struct   {
  228.    WORD   code;
  229.    UBYTE  *message;
  230.    } errorcodes[] = {
  231.  
  232.       103,    "insufficient free store",
  233.       104,    "task table full",
  234.       120,    "argument line invalid or too long",
  235.       121,    "file is not an object module",
  236.       122,    "invalid resident library during load",
  237.       203,    "object already exists",
  238.       204,    "directory not found",
  239.       205,    "object not found",
  240.       206,    "invalid window",
  241.       210,    "invalid stream component name",
  242.       212,    "object not of required type",
  243.       213,    "disk not validated",
  244.       214,    "disk write-protected",
  245.       215,    "rename across devices attempted",
  246.       216,    "directory not empty",
  247.       218,    "device not mounted",
  248.       220,    "comment too big",
  249.       221,    "disk full",
  250.       222,    "file is protected from deletion",
  251.       223,    "file is protected from writing",
  252.       224,    "file is protected from reading",
  253.       225,    "not a DOS disk",
  254.       226,    "no disk in drive",
  255.       209,    "packet request type unknown",
  256.       211,    "invalid object lock",
  257.       219,    "seek error",
  258.       232,    "no more entries in directory",
  259.       0, 0 };
  260.  
  261. /*
  262.  * Globals
  263.  */
  264.  
  265. UBYTE     work[514];
  266. UBYTE     work2[514];
  267. UBYTE     *args[ 5 ];   /* AZTEC doesn't allocate any more argv's than
  268.                            appear on command line, so we use our own array */
  269. /*
  270.  * MyCli globals
  271.  */
  272. struct   FileHandle     *mycli_infp;      /* all i/o goes thru these two */
  273. struct   FileHandle     *mycli_outfp;
  274.  
  275. UBYTE       prompt_string[74];      /* holds string to display prompt */
  276. UBYTE       chain_string[74];       /* holds character to chain commands */
  277. UBYTE       path_string[74];        /* holds string for search path */
  278. UBYTE       current_directory[74];  /* holds current directory string */
  279. UBYTE       cmdbuf[15][74];         /* queue of last 16 commands */
  280. WORD        mycli_id;               /* process id of mycli */
  281. WORD        lsmode = 0;             /* boolean 1=ls()   0=dir() */
  282. WORD        moremode = 0;           /* boolean 1=more() 0=type() */
  283. WORD        quit = 0;               /* boolean 1=quit recursion 0=no */
  284. WORD        indent = 0;             /* indentation for ls command */
  285. WORD        currcmd = 0;            /* current command for queue */
  286.  
  287. #ifdef MODEM
  288. /*
  289.  * Terminal emulator stuff
  290.  */
  291. struct   Message        *mymessage;
  292. struct   IOExtSer       *ModemReadRequest;
  293. struct   IOExtSer       *ModemWriteRequest;
  294.  
  295. UBYTE  *WelcomeMessage = "Entering Terminal Mode\nUse ^C for command mode\n";
  296. UBYTE  *GoodbyeMessage = "Disconnected\n";
  297. UBYTE  *OfflineMessage = "--- Offline ---\n";
  298. UBYTE  *OnlineMessage  = "--- Online ---\n";
  299.  
  300. UBYTE     rs_in[2], rs_out[2];
  301. WORD      bdoneflag      = 0;
  302. WORD      TermEcho       = 0;
  303. WORD      modem_online   = 0;
  304. WORD      capturing_file = 0;
  305. struct    FileHandle     *capture_fp;
  306. #endif
  307.  
  308. /* -------------------------------------
  309.  * Start of function Main()
  310.  * -------------------------------------
  311.  */
  312. main(argc, argv)
  313. int   argc;
  314. UBYTE *argv[];
  315. {
  316. UBYTE  *nextptr;
  317. UBYTE  *ptr;
  318. WORD   i;
  319. UBYTE  cmd_string[74];
  320.  
  321. if ( argc != 6 )
  322.    {
  323.    args[1] = "505"; args[2] = "136";
  324.    args[3] = "134"; args[4] = "64";
  325.    args[5] = "1";
  326.    argc = 6;
  327.    }
  328. else
  329.    for( i = 1; i < argc; i++)
  330.       args[ i ] = argv[ i ];
  331.  
  332. sprintf(work, "Raw:%s/%s/%s/%s/MyCli[%s]",
  333.         args[argc-5], args[argc-4], args[argc-3], args[argc-2], args[argc-1]);
  334.  
  335. mycli_id   = atoi(args[ argc-1 ]);
  336. mycli_infp = Open(work, MODE_NEWFILE);
  337.  
  338. if (mycli_infp == 0)
  339.    exit(1L);
  340.  
  341. mycli_outfp = mycli_infp;
  342. strcpy( work, "V1.0 By\nMike Schwartz\nV2.0 by\nRick Wirch\n\xa91986\n");
  343. WriteWork();
  344.  
  345. for ( i = 0; i < 16; i++)
  346.    cmdbuf[ i ][ 0 ] = '\0';
  347.  
  348. /* This is the default character for chaining commands */
  349. set( "chain ,");
  350.  
  351. /* This is the default MyCLI prompt */
  352. set( "prompt $e[1;32m$p>$n ");
  353.  
  354. /* This is the default search path for the AUTOEXEC.BAT file */
  355. batchfile( "autoexec.bat" );
  356.  
  357. /* This is the default startup directory for MyCli */
  358. cd( "df0:" );
  359.  
  360. /* This is the default search path for commands */
  361. set( "path RAM:;.;SYS:C/;" );
  362.  
  363. if ( mycli_id == 1 )                   /* first time MyCli is executed */
  364.    {
  365.    md( "RAM:C" );                      /* put run command in ramdisk */
  366.    copy( "SYS:c/run RAM:C/run" );      /* and make system use it for Execute */
  367.    executive( "ASSIGN C: RAM:C" );     /* force Execute to look in RAM: */
  368.    }
  369.  
  370. /* Main program loop */
  371.  
  372. while (TRUE)
  373.    {
  374.    showprompt();                       /* show the custom prompt */
  375.    getcommand( cmd_string );           /* get a command from the user */
  376.  
  377.    nextptr = cmd_string;               /* execute chained commands */
  378.    while ( *nextptr )
  379.       {
  380.       for ( ptr = nextptr; *ptr && *ptr != chain_string[ 0 ]; ptr++ )
  381.          ;
  382.       if ( *ptr )
  383.          *ptr++ = '\0';
  384.       CommandInterpreter( nextptr );   /* shuck off command to execute */
  385.       nextptr = ptr;
  386.       }                                /* end of while their is a string */
  387.    }
  388.  
  389. }                                      /* end of function main() */
  390.  
  391. /* -------------------------------------------------------
  392.  * Miscellaneous functions for internal commands or Main()
  393.  * -------------------------------------------------------
  394.  */
  395.  
  396. /*
  397.  * Declaring fh as a local in this routine, batch files may be nested
  398.  * as deep as the stack and memory will allow.  This is a simple batchfile
  399.  * executer ( that is it does not understand IF, SKIP, .KEY, etc. )
  400.  * but it does understand MyCLI internal commands, which Execute does not.
  401.  */
  402. VOID batchfile(batchname)
  403. UBYTE  *batchname;
  404. {
  405. struct   FileHandle *fh;
  406. register WORD       i;
  407. WORD     done;
  408. UBYTE    buf[74];
  409.  
  410. fh = Open(batchname, MODE_OLDFILE);
  411. if ( fh == NULL )
  412.    return;
  413.  
  414. done = FALSE;
  415. while ( !done )
  416.    {
  417.    for (i = 0; i < 70; i++)
  418.       {
  419.       if (Read(fh, &buf[i], 1L) == 0)
  420.          {
  421.          Close( fh );
  422.          done = TRUE;
  423.          break;
  424.          }
  425.       if (buf[ i ] == 0x0a)
  426.          break;
  427.       }
  428.    buf[ i ] = '\0';
  429.    showprompt();
  430.    sprintf(work, "%s\n", buf);
  431.    WriteWork();
  432.    CommandInterpreter( buf );
  433.    }
  434. }
  435.  
  436. /*
  437.  * Scan through the command table for the string and invoke the function
  438.  *    to do the actual work of the command.  Each of these commands is
  439.  *    defined below, and the functions each take a pointer to the
  440.  *    string containing the arguments passed the command line.
  441.  */
  442. VOID CommandInterpreter( command )
  443. UBYTE  *command;
  444. {
  445. struct FileHandle *oldfile;
  446. struct FileHandle *tempfh;
  447. WORD i;
  448. WORD found;
  449. UBYTE *ptr;
  450. UBYTE *pc;
  451. UBYTE *name;
  452. UBYTE trashbuf[74];
  453.  
  454. strcpy( trashbuf, command);
  455. command = stpblk( trashbuf );
  456.  
  457. found = FALSE;
  458. oldfile = NULL;
  459.  
  460. for ( ptr = command; *ptr && *ptr != '>' && *ptr != '<'; ptr++ )
  461.    ;
  462.  
  463. if ( (*ptr == '>' || *ptr == '<') && *(ptr-1) == ' ' )
  464.    {                                   /* do file redirection */
  465.    oldfile = mycli_outfp;              /* save old i/o handle */
  466.    name = stpblk( ptr + 1);            /* skip any leading blanks */
  467.    for ( pc = name; *pc && *pc != ' '; pc++ )
  468.       ;                                /* find end of redirection name */
  469.    if ( *pc )
  470.       *pc++ = '\0';
  471.    tempfh = Open( name, MODE_NEWFILE); /* open redirection */
  472.    if ( tempfh == NULL)
  473.       {
  474.       strcpy( work, "Can't open redirection file!\n");
  475.       WriteWork();
  476.       return;
  477.       }
  478.    if ( *ptr == '>' )
  479.       mycli_outfp= tempfh;             /* redirect */
  480.    else
  481.       mycli_infp = tempfh;
  482.  
  483.    strcpy( ptr-1, pc );                /* delete out the redir. stuff */
  484.    }                                   /* end of redirection open */
  485.  
  486. ptr = command;                         /* point to beginning of cmd string */
  487.  
  488. /* Look for the command in the command table built into MyCLI */
  489. for (i=0; command_table[ i ].cmdname[ 0 ] != '\0'; i++)
  490.    if (strncmp( ptr, &command_table[ i ].cmdname[ 0 ],
  491.                 strlen(&command_table[ i ].cmdname[ 0 ]) ) == 0)
  492.       {
  493.       found = TRUE;
  494.       ptr = stpblk( &command[ strlen(command_table[i].cmdname) ] );
  495.       (*command_table[ i ].cmdfunc)( ptr );     /* call the command */
  496.       }
  497.  
  498. if ( !found)                           /* Not found, look for it on disk */
  499.    executive( command );
  500.  
  501. if ( oldfile )                         /* close the redirection file(s) */
  502.    {
  503.    if ( mycli_outfp != oldfile )
  504.       Close( mycli_outfp );
  505.    if ( mycli_infp  != oldfile )
  506.       Close( mycli_infp );             /* close up any redirection */
  507.    mycli_outfp = mycli_infp = oldfile; /* restore the defaults */
  508.    }
  509.  
  510. }
  511.  
  512. /*
  513.  * This function displays a description of the DOS error when it happens
  514.  */
  515. VOID doserr()
  516. {
  517.  
  518. sprintf( work2, "%d", IoErr());
  519. whatis( work2 );
  520. }
  521.  
  522. /* This function is responsible for executing commands that are not
  523.  * internal to MyCLI.  It performs the path expansion and understands
  524.  * .BAT or .CLI extensions.
  525.  */
  526. VOID executive(s)
  527. UBYTE  *s;
  528. {
  529. register UBYTE    *pc;
  530. register UBYTE    *wptr;
  531. register WORD     found;
  532. register WORD     batchON;
  533. struct   FileLock *fl;
  534. struct     FileLock *ramlock;
  535.  
  536. if ( *s == '\0' )
  537.    return;                 /* no command so just return */
  538.  
  539. /* get the first token off of the command line into work. */
  540. pc = &work[ 0 ];
  541. while ( *s && (*pc = *s++) != ' ' )
  542.    pc++;
  543. *pc = '\0';                /* null terminate work[] */
  544. s = stpblk( s );           /* skip spaces , s points at arguments */
  545.  
  546. strcpy( work2, work );     /* save first token in work2 */
  547.  
  548. /* check for MyCLI batch file invocation. */
  549. strcpy( work, work2 );
  550. strcat( work, ".bat" );
  551. fl = Lock(work, ACCESS_READ);
  552. if (fl != NULL )           /* MyCLI batch file exists */
  553.    {
  554.    UnLock(fl);             /* free the lock obtained */
  555.    batchfile(work);        /* execute the batch file */
  556.    return;                 /* done our work */
  557.    }
  558.  
  559. /* .cli files are batch files to be run by the */
  560. /* standard cli, using the execute command. */ 
  561. strcpy(work, work2);       /* preserve the first token again */
  562. strcat(work, ".cli");
  563. fl = Lock(work, ACCESS_READ);
  564. if (fl != NULL)            /* cli batch file exists */
  565.    {
  566.    batchON = TRUE;
  567.    strcpy( work2, work );  /* put batch name first */
  568.    strcat( work2, " ");    /* add a space before the params */
  569.    strcat( work2, s);      /* add the params */
  570.    strcpy( work , "execute");
  571.    UnLock( fl );           /* free the lock obtained */
  572.    }
  573. else
  574.    {
  575.    batchON = FALSE;
  576.    found = FALSE;
  577.    /* do the path search */
  578.    pc = &path_string[ 0 ];
  579.    while ( *pc )
  580.       {
  581.       wptr = &work[ 0 ];     /* set wptr to start of work[] */
  582.       while ( *pc && (*wptr = *pc) != ';' )
  583.          pc++, wptr++;        /* copy path prefix into work array */
  584.       *wptr = '\0';           /* null terminate work[] */
  585.       pc++;                   /* advance over the semi-colon */
  586.       if ( work[ 0 ] == '.' ) /* dot means current dir */
  587.          work[ 0 ] = '\0';
  588.       strcat( work, work2 );  /* add the command */
  589.       fl = Lock( work, ACCESS_READ);
  590.       if ( fl != NULL)
  591.          {
  592.          UnLock( fl);
  593.          found = TRUE;
  594.          break;
  595.          }
  596.       }                       /* end of while */
  597.    if ( !found )
  598.       strcpy( work, work2);   /* restore the command in work[] */
  599.    strcpy( work2, s);         /* put the params in work2[] */
  600.    }                          /* end of else clause */
  601.  
  602. strcat( work, " < * ");       /* redirect input */
  603.  
  604. if ( *work2 )
  605.    strcat( work, work2 );     /* add the parameters */
  606.  
  607. ramlock = Lock( "RAM:C", ACCESS_READ );
  608. if ( ramlock )
  609.     UnLock( ramlock );
  610. else
  611.     batchON = FALSE;
  612.     
  613. if ( batchON )
  614.    Execute( "SYS:C/assign C: SYS:C", 0L, mycli_outfp );
  615.  
  616. if ( !Execute( work, 0L, mycli_outfp) )
  617.    doserr();
  618.  
  619. if ( batchON )
  620.    Execute( "SYS:C/assign C: RAM:C", 0L, mycli_outfp );
  621. }
  622.  
  623. /*
  624.  * If a definition for the function key fkey exists ( 0-19), then
  625.  * the translation for the function key is copied to the string
  626.  * s, and this function returns 1.  Otherwise, no translation
  627.  * exists, and this function returns 0;
  628.  */
  629. WORD  function_key( fkey, s )
  630. WORD  fkey;
  631. UBYTE *s;
  632. {
  633. register WORD i;
  634.  
  635. if ( function_key_definitions[ fkey ] != 0)
  636.    {
  637.    for( i = 0; function_key_definitions[ fkey ][ i ] != 0; i++)
  638.       s[ i ] = function_key_definitions[ fkey ][ i ];
  639.    s[ i ] = '\0';
  640.    return( TRUE );
  641.    }
  642. return( FALSE );
  643. }
  644.  
  645. /* This function is like a read of the keyboard except
  646.  * that if no key is pressed it immediately returns a zero
  647.  */
  648. UBYTE  scr_csts()
  649. {
  650. UBYTE inbuf;
  651.  
  652. if (WaitForChar(mycli_infp, 1L) == 0)
  653.    return( 0 );
  654. Read(mycli_infp, &inbuf, 1L);
  655. return( inbuf );
  656. }
  657.  
  658. /* This function uses the string 'prompt_string' and its embedded meaning
  659.  * to display a user defined prompt
  660.  */
  661. VOID showprompt()
  662. {
  663. register UBYTE *pc;
  664. struct DateStamp dss;
  665.  
  666. pc = prompt_string;
  667.  
  668. while ( TRUE )
  669.    {
  670.    switch(*pc)
  671.       {
  672.       case '\0':
  673.          return;
  674.       case '$':
  675.          pc++;
  676.          switch( *pc )
  677.             {
  678.             case '\0':
  679.                return;
  680.             case 'b': case 'B':     /* backspace */
  681.                strcpy( work, "\x08" );
  682.                break;
  683.             case 'd': case 'D':     /* current date */
  684.                DateStamp(&dss);
  685.                dates(work, &dss);
  686.                break;
  687.             case 'e': case 'E':     /* escape character */
  688.                strcpy( work, "\x1b");
  689.                break;
  690.             case 'n': case 'N':     /* normal video */
  691.                strcpy( work, "\x1b[0m");
  692.                break;
  693.             case 'p': case 'P':     /* current path */
  694.                sprintf(work, "%s", current_directory);
  695.                break;
  696.             case 'r': case 'R':     /* reverse video */
  697.                strcpy( work, "\x1b[7m");
  698.                break;
  699.             case 't': case 'T':     /* current time */
  700.                DateStamp(&dss);
  701.                times(work, &dss);
  702.                break;
  703.             case 'v': case 'V':
  704.                strcpy( work, "MyCli rev. 2.0");
  705.                break;
  706.             case '_':
  707.                strcpy(work, "\n");
  708.                break;
  709.             }
  710.          pc++;
  711.          WriteWork();
  712.          continue;
  713.       default:
  714.          sprintf(work, "%c", *pc++);
  715.          WriteWork();
  716.          continue;
  717.       }
  718.    }     /* end of while( TRUE ) loop */
  719. }
  720.  
  721. /* This function is called at the end of every line displayed to the
  722.  * window, it allows the user to pause that output or abort it.
  723.  */
  724. WORD  pause()
  725. {
  726. UBYTE inbuf;
  727.  
  728. switch( scr_csts() )
  729.    {
  730.    case ' ':
  731.       while ( (inbuf = scr_csts()) != ' ' )
  732.          if (inbuf == ESC || inbuf == BRK)
  733.             return( FALSE );
  734.       return( TRUE );
  735.    case ESC: case BRK:
  736.       return( FALSE );
  737.    default:
  738.       return( TRUE );
  739.    }
  740. }
  741.  
  742. /*
  743.  * build an appropriate file specification for output file
  744.  */
  745. VOID makename( dirstr, filestr)
  746. UBYTE *dirstr;
  747. UBYTE *filestr;
  748. {
  749. register UBYTE *pc;
  750.  
  751. pc = &dirstr[ strlen(dirstr)-1 ];
  752. if (*pc == ':')            /* from device:filespec? */
  753.    strcat( dirstr, filestr);
  754. else                       /* append a slash, but don't want '//' */
  755.    {
  756.    if (*pc != '/')
  757.       strcat(dirstr, "/");
  758.    strcat(dirstr, filestr);
  759.    }
  760. }
  761.  
  762. /* This function gets a command line from the user.  It performs the
  763.  * command line editing, simple history ability, function key expansion,
  764.  * and other assorted fun things.
  765.  */
  766. VOID getcommand(s)
  767. UBYTE *s;
  768. {
  769. register WORD col;
  770. register WORD i;
  771. register WORD insert;
  772. UBYTE event_buffer[ 32 ];
  773. UBYTE c;
  774.  
  775. insert = FALSE;
  776.  
  777. for ( col = 0; col < 72; col++)
  778.    s[ col ] = '\0';              /* initialize string to NULLs */
  779. col = 0;
  780.  
  781. while ( TRUE )
  782.    {
  783.    Read(mycli_infp, &c, 1L);
  784.    switch( c )
  785.       {
  786.       case 8:              /* Backspace key */
  787.          if (col)
  788.             {
  789.             Write(mycli_outfp, "\x08\x9bP", 3L);
  790.             col--;
  791.             s[ col ] = '\0';
  792.             strcat( s, &s[ col+1 ]);
  793.             }
  794.          continue;
  795.       case 0x01: case 0x09:            /* CTRL-A, CTRL-I or TAB key */
  796.          insert = !insert;
  797.          continue;
  798.       case 0x7f:                       /* DEL key */
  799.          Write(mycli_outfp, "\x9bP", 2L);
  800.          s[ col ] = '\0';
  801.          strcat( s, &s[ col+1 ]);
  802.          continue;
  803.       case 10: case 13:                /* CR or LF are end line chars */
  804.          Write(mycli_outfp, "\n", 1L);
  805.          if ( *s )
  806.             {
  807.             strcpy( &cmdbuf[ currcmd ][ 0 ], s );
  808.             currcmd = ++currcmd & 15;  /* make counter wrap */
  809.             }
  810.          break;
  811.       case ESC: case 24:               /* ESC or ^X are kill line chars */
  812.          while( col )
  813.             {
  814.             Write( mycli_outfp, "\x08 \x08", 3L);
  815.             col--;
  816.             s[ col ] = '\0';
  817.             }
  818.          continue;
  819.       case 0x9b:
  820.          Read( mycli_infp, &c, 1L);
  821.          if ( isdigit(c) )
  822.             {
  823.             i = 0;
  824.             while ( isdigit(c) )
  825.                {
  826.                event_buffer[ i++ ] = c;
  827.                Read( mycli_infp, &c, 1L);
  828.                }
  829.             event_buffer[ i ] = '\0';
  830.             if ( function_key( atoi(event_buffer), s) )
  831.                {
  832.                sprintf( work, "%s\n", s);
  833.                WriteWork();
  834.                return;
  835.                }
  836.             }
  837.          else
  838.             switch( c)
  839.                {
  840.                case ' ':      /* shifted cursor left and right */
  841.                   Read( mycli_infp, &c, 1L);
  842.                   if ( c == 'A') /* shift left */
  843.                      while ( col )
  844.                         {
  845.                         Write( mycli_outfp, "\x08", 1L);
  846.                         col--;
  847.                         }
  848.                   else           /* shift right */
  849.                      while ( col < 70 && s[ col ] != '\0' )
  850.                         {
  851.                         Write(mycli_outfp, "\x9bC", 2L);
  852.                         col++;
  853.                         }
  854.                   break;
  855.                case 'A': case 'B':
  856.                   if ( c == 'A' )
  857.                      currcmd = --currcmd & 15;
  858.                   else
  859.                      currcmd = ++currcmd & 15;
  860.                   for ( i = 0; i < 72; i++)
  861.                      s[ i ] = '\0';
  862.                   strcpy( s, &cmdbuf[ currcmd ][ 0 ]);
  863.                   col = strlen( s );
  864.                   Write( mycli_outfp, "\r\x9bK", 3L);
  865.                   showprompt();
  866.                   strcpy( work, s);
  867.                   WriteWork();
  868.                   break;
  869.                case 'C':                     /* cursor right */
  870.                   if ( col < 70 && s[ col ] != '\0' )
  871.                      {
  872.                      Write(mycli_outfp, "\x9bC", 2L);
  873.                      col++;
  874.                      }
  875.                   break;
  876.                case 'D':                     /* cursor left */
  877.                   if ( col )
  878.                      {
  879.                      Write(mycli_outfp, "\x08", 1L);
  880.                      col--;
  881.                      }
  882.                   break;
  883.                case '?':
  884.                   strcpy( s, "help");
  885.                   return;
  886.                }
  887.             continue;
  888.          default:
  889.             if ( c >= ' ' && c <= '~' )
  890.                if (insert)
  891.                   {
  892.                   if ( strlen(s) < 70)
  893.                      {
  894.                      strcpy( work2, &s[ col ]);
  895.                      s[ col++ ] = c;
  896.                      s[ col ] = '\0';
  897.                      strcat( s, work2);
  898.                      Write( mycli_outfp, "\x9b@", 2L);
  899.                      }
  900.                   }
  901.                else if ( col < 70)
  902.                   s[ col++ ] = c;
  903.             Write( mycli_outfp, &c, 1L);
  904.             continue;
  905.          }
  906.       break;
  907.       }
  908.    }
  909.  
  910. /* --------------------------------------------------------------
  911.  * Start of MyCLI internal functions
  912.  * --------------------------------------------------------------
  913.  */
  914.  
  915. #ifdef MODEM
  916. VOID capture(s)
  917. UBYTE  *s;
  918. {
  919.    if (!modem_online) {
  920.       strcpy( work, "\x1b[33mCapture Error: not online\x1b[0m\n");
  921.       WriteWork();
  922.       }
  923.    else if (capturing_file) {
  924.       Close(capture_fp);
  925.       strcpy( work, "\x1b[33mCapture Completed\x1b[0m\n");
  926.       WriteWork();
  927.       capturing_file = 0;
  928.       }
  929.    else {
  930.       capture_fp = Open(s, MODE_NEWFILE);
  931.       if (capture_fp == 0)
  932.          doserr();
  933.       else {
  934.          capturing_file = !0;
  935.          strcpy( work,"\x1b[33mCapturing File - capture again to terminate\x1b[0m\n");
  936.          WriteWork();
  937.          }
  938.       }
  939. }
  940. #endif
  941.  
  942. VOID cd(s)
  943. UBYTE *s;
  944. {
  945. register WORD                 i;
  946. register struct FileLock      *worklock;
  947. register struct FileInfoBlock *fib;
  948.  
  949. if ( *s == '\0' )
  950.    {
  951.    sprintf(work, "%s\n", current_directory);
  952.    WriteWork();
  953.    return;
  954.    }
  955.  
  956. strcpy( work2, current_directory);
  957. fib = (struct FileInfoBlock *)AllocMem( (long)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
  958.  
  959. while ( *s == '/')                     /* go up directory path one dir */
  960.    {
  961.    s++;
  962.    for ( i = strlen(current_directory);
  963.         current_directory[ i ] != '/' && current_directory[ i ] != ':' && i ;
  964.         i--);
  965.    if ( current_directory[ i ] == ':')
  966.       current_directory[ i+1 ] = '\0';
  967.    else
  968.       current_directory[ i ] = '\0';
  969.    }
  970.  
  971. if ( stpchr(s, ':') == 0 )             /* no ':' in the path */
  972.    {
  973.    if ( *s != '\0' )
  974.       makename( current_directory, s); /* add string to current dir */
  975.    }
  976. else
  977.    strcpy(current_directory, s);       /* string is new current dir */
  978.  
  979. worklock = Lock(current_directory, ACCESS_READ);
  980. if (worklock == 0)
  981.    {
  982.    strcpy(current_directory, work2);
  983.    doserr();
  984.    }
  985. else if ( Examine(worklock, fib) )
  986.    {
  987.    if (fib->fib_DirEntryType > 0L)
  988.       worklock = CurrentDir(worklock);
  989.    else
  990.       {
  991.       strcpy( work, "\x1b[33mCD Error: not a directory!\x1b[0m\n");
  992.       WriteWork();
  993.       strcpy(current_directory, work2);
  994.       }
  995.    }
  996. else
  997.    doserr();
  998.  
  999. if ( worklock )
  1000.    UnLock( worklock );
  1001. if ( fib )
  1002.    FreeMem( fib, (long)sizeof(struct FileInfoBlock) );
  1003. }
  1004.  
  1005. VOID copy(s)
  1006. UBYTE *s;
  1007. {
  1008. register    LONG        iosize;
  1009. register    LONG        actual;
  1010. register    UBYTE       *copybuf;
  1011. register    UBYTE       *pc;
  1012. struct      FileLock    *worklock;
  1013. struct      FileInfoBlock *fib;
  1014. struct      FileHandle  *copyin;
  1015. struct      FileHandle  *copyout;
  1016.  
  1017. copyin = copyout = NULL;
  1018.  
  1019. if ( strncmp( s, "from", 4 ) == 0 )          /* remove keyword 'from' */
  1020.    s = stpblk( s + 4 );
  1021.  
  1022. for ( pc = s; *pc && !isspace( *pc ); pc++ )
  1023.    ;
  1024. *pc++ = '\0';
  1025. pc = stpblk( pc );
  1026.  
  1027. if ( strncmp( pc, "to", 2 ) == 0 )           /* remove keyword 'to' */
  1028.    pc = stpblk( pc + 2 );
  1029.  
  1030. /*  check 'from' filename for console. */
  1031. if (strncmp(s, "*", 1) == 0)
  1032.    copyin = mycli_infp;
  1033. else
  1034.    copyin = Open(s, MODE_OLDFILE);
  1035.  
  1036. if (copyin == NULL)
  1037.    {
  1038.    doserr();
  1039.    return;
  1040.    }
  1041.  
  1042. /* second parameter */
  1043. if (strncmp(pc, "*", 1) == 0)    /* the console device */
  1044.    copyout = mycli_outfp;
  1045. else if (*pc == '\0')            /* no second parameter so put it here */
  1046.    {
  1047.    pc = &s[ strlen(s)-1 ];       /* end of string */
  1048.    while (pc != s && *pc != ':' && *pc != '/')
  1049.       pc--;
  1050.    if ( pc != s )
  1051.       {
  1052.       pc++;                               /* move forward over '/' or ':' */
  1053.       strcpy(work, current_directory);    /* save directory in work */
  1054.       makename( work, pc);                /* add filename to dir */
  1055.       copyout = Open(work, MODE_NEWFILE);
  1056.       }
  1057.    }
  1058. else                             /* either a file or a directory name */
  1059.    {
  1060.    strcpy( work, pc);            /* put file name in work */
  1061.    worklock = Lock( work, ACCESS_READ);
  1062.    if ( worklock )
  1063.       {
  1064.       fib = (struct FileInfoBlock *)AllocMem( (long)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
  1065.       if (!Examine( worklock, fib))
  1066.          doserr();
  1067.       else
  1068.          {
  1069.          if ( fib->fib_DirEntryType > 0L)  /* if it is a directory */
  1070.             {
  1071.             pc = &s[ strlen(s)-1 ];   /* end of string of file to be copied*/
  1072.             while (pc != s && *pc != ':' && *pc != '/')
  1073.                pc--;
  1074.             if ( *pc == ':' || *pc == '/' )
  1075.                pc++;
  1076.             makename( work, pc);    /* add file name to dir name */
  1077.             }
  1078.          }
  1079.       UnLock(worklock);
  1080.       FreeMem( fib, (long)sizeof(struct FileInfoBlock) );
  1081.       }
  1082.    copyout = Open( work, MODE_NEWFILE);
  1083.    }
  1084.  
  1085. if (copyout == NULL)
  1086.    {
  1087.    doserr();
  1088.    Close(copyin);
  1089.    return;
  1090.    }
  1091.  
  1092. /*
  1093.  * here is how to determine the length of a
  1094.  * file.  This is the most desirable Amount
  1095.  * to read from the from file, because it
  1096.  * requires one head seek, and allows the
  1097.  * entire track buffer to be used for the
  1098.  * read.
  1099.  */
  1100. if ( copyin == mycli_infp)
  1101.    iosize = 1;
  1102. else
  1103.    {
  1104.    iosize = Seek(copyin, 0L, OFFSET_END);
  1105.    iosize = Seek(copyin, 0L, OFFSET_BEGINING);
  1106.    }
  1107.  
  1108. /*
  1109.  * maybe there isn't enough memory to hold
  1110.  * the entire from file.  the following
  1111.  * algorithm determines whether 1/2 the
  1112.  * file file, 1/4, 1/8, etc., will fit
  1113.  * in memory at a time.  if 512 bytes can't
  1114.  * be allocated, then there is not enough
  1115.  * memory to do the copy at all.
  1116.  */
  1117. do
  1118.    {
  1119.    copybuf = AllocMem(iosize, MEMF_PUBLIC|MEMF_CLEAR);
  1120.    if (copybuf == 0)
  1121.       iosize = iosize/2;
  1122.    }
  1123. while( copybuf == 0 && iosize > 512 );
  1124.  
  1125. if (copybuf == 0)
  1126.    {
  1127.    strcpy( work, "\x1b[33mCopy Error: Not Enough Memory\x1b[0m\n");
  1128.    WriteWork();
  1129.    }
  1130. else
  1131.    do
  1132.       {
  1133.       actual = Read(copyin, copybuf, iosize);
  1134.       if (Write(copyout, copybuf, actual) != actual)
  1135.          {
  1136.          doserr();
  1137.          break;
  1138.          }
  1139.       if (copyin == mycli_infp)
  1140.          {
  1141.          Write( mycli_outfp, copybuf, (long)actual);
  1142.          if ( *copybuf == 28 )                        /* 28 is a ^\ */
  1143.             {
  1144.             Write( mycli_outfp, "\n", 1L);
  1145.             actual = 0;
  1146.             }
  1147.          }
  1148.       }
  1149.    while (actual == iosize);
  1150.  
  1151. if (copyin &&  copyin != mycli_infp)
  1152.    Close(copyin);
  1153. if (copyout && copyout != mycli_outfp)
  1154.    Close(copyout);
  1155. if ( copybuf )
  1156.    FreeMem(copybuf, iosize);
  1157. }
  1158.  
  1159. /*
  1160.  * get the date and make it into a printable string
  1161.  */
  1162. static UBYTE *months[12] = {
  1163.    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1164.    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1165.    };
  1166.  
  1167. static UBYTE dayspermonth2[12] = {   /* non leap years */
  1168.    31, 28, 31, 30, 31, 30,
  1169.    31, 31, 30, 31, 30, 31
  1170.    };
  1171.  
  1172. static UBYTE *dayofweek[] = {
  1173.    "Sunday ", "Monday ", "Tuesday ", "Wednesday ", "Thursday ",
  1174.    "Friday ", "Saturday "
  1175.    };
  1176.  
  1177. static LONG  day, month, year;
  1178.  
  1179. dates(s, dss)
  1180. UBYTE  *s;
  1181. struct DateStamp *dss;
  1182. {
  1183. register LONG temp;
  1184.  
  1185.    day = (long)dss->ds_Days;
  1186.    if( day < 0 ) {          /* < 0 around the year 2045 */
  1187.       strcpy( s,"Date out of range");
  1188.       return;
  1189.    }
  1190.    for( year = 78; (temp = 365 + ((( year & 3) == 0) ? 1 : 0)) <= day;)
  1191.    {
  1192.       year++;
  1193.       day -= temp;
  1194.    }
  1195.    for( month = 0; day >= dayspermonth2[ month ]; month++)
  1196.    {
  1197.       day -= dayspermonth2[ month ];
  1198.       if( (month == 1) && ((year & 3) == 0) ) {
  1199.          day--;            /* leap year */
  1200.          if( day < 0 ) {   /* ugly, but needed */
  1201.            day = 28;
  1202.            break;
  1203.          }
  1204.       }
  1205.    }
  1206.    year += 1900;
  1207.    sprintf(s, "%2ld-%3s-%4ld", day+1, months[ month ], year);
  1208. }
  1209.  
  1210. VOID date(s)
  1211. UBYTE *s;
  1212. {
  1213. struct   DateStamp   dss;
  1214.  
  1215. DateStamp(&dss);
  1216. strcpy( work, dayofweek[ ABS(dss.ds_Days % 7) ] );
  1217. dates( work+strlen(work), &dss );
  1218.  
  1219. #ifdef MOON
  1220. strcat( work, ".  The moon is ");
  1221. strcat( work, moon() );
  1222. #endif   /* MOON */
  1223.  
  1224. strcat(work, ".\n");
  1225. WriteWork();
  1226. }
  1227.  
  1228. VOID define_function_key(s)
  1229. UBYTE  *s;
  1230. {
  1231. register UBYTE *ptr;
  1232. register WORD  i;
  1233.  
  1234. ptr = s;                                     /* set up register */
  1235. if ( *ptr == '\0')
  1236.    {
  1237.    for ( i = 0; i < 20; i++)
  1238.       if (function_key_definitions[ i ])
  1239.          {
  1240.          sprintf(work, "F%-2d = %s\n", i+1, function_key_definitions[ i ]);
  1241.          WriteWork();
  1242.          }
  1243.    return;
  1244.    }
  1245.  
  1246. i = atoi( ptr + 1 );
  1247. if ( ( *ptr != 'f' && *ptr != 'F') || (i < 1 || i > 20) )
  1248.    {
  1249.    strcpy( work,"\x1b[33mInvalid function key specified\x1b[0m\n");
  1250.    WriteWork();
  1251.    return;
  1252.    }
  1253.  
  1254. ptr++;
  1255. if ( function_key_definitions[ --i ] )
  1256.    {
  1257.    FreeMem( function_key_definitions[ i ], (long)strlen(function_key_definitions[ i ])+1 );
  1258.    function_key_definitions[ i ] = 0L;
  1259.    }
  1260. while ( isdigit( *ptr ) )
  1261.    ptr++;
  1262. ptr = stpblk( ptr );
  1263. if ( *ptr )
  1264.    {
  1265.    function_key_definitions[ i ] = AllocMem((long)strlen(ptr)+1, MEMF_PUBLIC|MEMF_CLEAR);
  1266.    if (function_key_definitions[ i ] == 0)
  1267.       {
  1268.       strcpy( work, "\x1b[33mDefine Error: not enough memory\x1b[0m\n");
  1269.       WriteWork();
  1270.       }
  1271.    else
  1272.       strcpy(function_key_definitions[ i ], ptr);
  1273.    }
  1274. }
  1275.  
  1276. VOID delete(s)
  1277. UBYTE *s;
  1278. {
  1279.  
  1280. if ( !DeleteFile(s) )
  1281.    doserr();
  1282. }
  1283.  
  1284. /* MyCLI 'list' command is like AmigaDOS 'list' */
  1285.  
  1286. VOID list(s)
  1287. UBYTE *s;
  1288. {
  1289.  
  1290. quit = 0;
  1291. dirfun(s);
  1292. }
  1293.  
  1294. /* MyCLI 'dir' is like AmigaDos 'dir'  */
  1295. VOID dir(s)
  1296. UBYTE *s;
  1297. {
  1298. register UBYTE *ptr;
  1299.  
  1300. quit = 0;
  1301. indent = 0;
  1302. ptr = s;
  1303. while ( *ptr )
  1304.    ptr++;                           /* go to end of string */
  1305. while ( ptr != s && *ptr != '-' && *ptr != 'o' )
  1306.    ptr--;                           /* search back for keyword */
  1307. if ( strncmp( ptr, "-r", 2) == 0 || strncmp( ptr, "opt a", 5) == 0 )
  1308.    {
  1309.    if ( ptr != s )
  1310.       ptr--;
  1311.    *ptr = '\0';
  1312.    lsmode = 2;
  1313.    }
  1314. else
  1315.    lsmode = 1;
  1316.  
  1317. dirfun(s);
  1318. lsmode = 0;
  1319. }
  1320.  
  1321.  
  1322. dirfun(s)
  1323. UBYTE  *s;
  1324. {
  1325. struct   FileLock       *worklock;
  1326. struct   FileInfoBlock  *fib;
  1327. LONG     bytecount, blockcount, filecount, dircount;
  1328. WORD     newline;
  1329. UBYTE    dirstr[74];
  1330.  
  1331. dircount = filecount = bytecount = blockcount = 0L;
  1332. newline  = 0;
  1333.  
  1334. if (*s == '\0')
  1335.    strcpy( s, current_directory);
  1336. worklock = Lock( s, ACCESS_READ);
  1337. if (worklock == 0)
  1338.    {
  1339.    doserr();
  1340.    return( 0);
  1341.    }
  1342.  
  1343. fib = (struct FileInfoBlock *)AllocMem( (long)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
  1344.  
  1345. if ( !Examine(worklock, fib))
  1346.    doserr();
  1347. else
  1348.    {
  1349.    if (fib->fib_DirEntryType < 0L)      /* if its a file */
  1350.       {
  1351.       showfib( fib);
  1352.       filecount++;
  1353.       bytecount += fib->fib_Size;
  1354.       blockcount += fib->fib_NumBlocks;
  1355.       }
  1356.    else                                /* else its a subdirectory */
  1357.       while(ExNext(worklock, fib))
  1358.          {
  1359.          if (fib->fib_DirEntryType > 0L && lsmode == 2)
  1360.             {
  1361.             if (newline )
  1362.                nextline( TRUE);
  1363.             sprintf( work,   "%s (Dir)", fib->fib_FileName);
  1364.             WriteWork();
  1365.             strcpy( dirstr, s);
  1366.             if ( dirstr[ strlen(dirstr)-1 ] != ':')
  1367.                strcat( dirstr, "/");
  1368.             strcat( dirstr, fib->fib_FileName );
  1369.             indent++;
  1370.             nextline( TRUE);
  1371.             dirfun( dirstr );
  1372.             }
  1373.          else
  1374.             {
  1375.             if ( lsmode)
  1376.                {
  1377.                if (fib->fib_DirEntryType > 0L)     /* if its a directory */
  1378.                   {
  1379.                   if ( newline)
  1380.                      nextline( TRUE);
  1381.                   sprintf( work, "%s (Dir)\n", fib->fib_FileName);
  1382.                   WriteWork();
  1383.                   newline = FALSE;
  1384.                   }
  1385.                else
  1386.                   {
  1387.                   sprintf( work, "%-30s ", fib->fib_FileName);
  1388.                   WriteWork();
  1389.                   if ( newline)
  1390.                      nextline( TRUE);
  1391.                   newline = !newline;
  1392.                   }
  1393.                }
  1394.             else
  1395.                {
  1396.                showfib( fib);
  1397.                bytecount += fib->fib_Size;
  1398.                blockcount += fib->fib_NumBlocks;
  1399.                if (fib->fib_DirEntryType <= 0L)
  1400.                   filecount++;
  1401.                else                    /* Djj */
  1402.                    {
  1403.                    dircount++;
  1404.                    blockcount++;
  1405.                    bytecount += 512L;
  1406.                    }
  1407.                }
  1408.             }
  1409.          if (!pause())
  1410.             quit = TRUE;
  1411.          if (quit)
  1412.             break;
  1413.          }           /* end of while */
  1414.  
  1415.    if ( !lsmode)
  1416.       {
  1417.       sprintf(work,"\n%3ld Directories -%3ld Files -%7ld Bytes -%6ld Blocks\n",
  1418.               dircount, filecount, bytecount, blockcount);
  1419.       WriteWork();
  1420.       }
  1421.    else
  1422.       {
  1423.       indent--;
  1424.       if ( newline)
  1425.          nextline( TRUE);
  1426.       else
  1427.          nextline( FALSE);
  1428.       }
  1429.    UnLock(worklock);
  1430.    }
  1431.  
  1432. FreeMem( fib, (long)sizeof(struct FileInfoBlock) );
  1433. }
  1434.  
  1435.  
  1436. showfib( infib)
  1437. struct FileInfoBlock *infib;
  1438. {
  1439.  
  1440. sprintf(work, "%-25s ", infib->fib_FileName);
  1441. WriteWork();
  1442.  
  1443. if (infib->fib_DirEntryType > 0L)
  1444.    sprintf(work, " (Dir) ");
  1445. else
  1446.    sprintf(work, "%6ld ", infib->fib_Size);
  1447. WriteWork();
  1448.  
  1449. sprintf(work, "%c%c%c%c ",
  1450.     (infib->fib_Protection & FIBF_READ)    ? '-' : 'r',
  1451.     (infib->fib_Protection & FIBF_WRITE)   ? '-' : 'w',
  1452.     (infib->fib_Protection & FIBF_EXECUTE) ? '-' : 'e',
  1453.     (infib->fib_Protection & FIBF_DELETE)  ? '-' : 'd');
  1454. WriteWork();
  1455.  
  1456. dates( work, &infib->fib_Date);
  1457. strcat(work, " ");
  1458. WriteWork();
  1459.  
  1460. times( work, &infib->fib_Date);
  1461. strcat(work, "\n");
  1462. WriteWork();
  1463. }
  1464.  
  1465. nextline( next)
  1466. WORD next;
  1467. {
  1468. register WORD i;
  1469.  
  1470. if ( next)
  1471.    Write( mycli_outfp, "\n", 1L);
  1472. else
  1473.    Write( mycli_outfp, "\r", 1L);
  1474. for ( i=0; i < indent; i++)
  1475.    Write( mycli_outfp, "  ", 2L);
  1476. }
  1477.  
  1478. VOID endcli(s)
  1479. UBYTE *s;
  1480. {
  1481. register WORD i;
  1482.  
  1483. #ifdef MODEM
  1484.    if (modem_online) {
  1485.       strcpy( work, "\x1b[33mTerminal Mode Error: Modem still online\x1b[0m\n");
  1486.       WriteWork();
  1487.       }
  1488.    else {
  1489. #endif
  1490.       for ( i = 0; i < 20; i++)
  1491.          if (function_key_definitions[ i ])
  1492.             FreeMem(function_key_definitions[ i ], (long)strlen(function_key_definitions[ i ])+1);
  1493.       if ( mycli_id == 1 )
  1494.          executive( "ASSIGN C: SYS:C" );
  1495.       Close( mycli_outfp);
  1496.       exit( 0L );
  1497. #ifdef MODEM
  1498.       }
  1499. #endif
  1500. }
  1501.  
  1502. VOID help(s)
  1503. UBYTE *s;
  1504. {
  1505. register WORD i;
  1506.  
  1507. strcpy( work, "\n\x1b[33m          MyCli Help\x1b[0m\n");
  1508. WriteWork();
  1509. for ( i = 0; help_messages[ i ]; i++)
  1510.    {
  1511.    sprintf(work, "%s\n", help_messages[ i ]);
  1512.    WriteWork();
  1513.    if ( !pause() )
  1514.       break;
  1515.    }
  1516. strcpy( work, "\x1b[33m          End of Help\x1b[0m\n");
  1517. WriteWork();
  1518. }
  1519.  
  1520. VOID md(s)
  1521. UBYTE *s;
  1522. {
  1523. register struct FileLock *worklock;
  1524.  
  1525. worklock = CreateDir(s);
  1526. if (worklock == 0)
  1527.    doserr();
  1528. else
  1529.    UnLock(worklock);
  1530. }
  1531.  
  1532. VOID more(s)
  1533. UBYTE *s;
  1534. {
  1535.  
  1536. if ( mycli_outfp == mycli_infp )          /* no redirection enables more */
  1537.    moremode = 1;
  1538. type(s);
  1539. moremode = 0;
  1540. }
  1541.  
  1542. VOID newcli(s)
  1543. UBYTE *s;
  1544. {
  1545. register WORD ypos;
  1546.  
  1547. if ( *s )
  1548.    sprintf( work, "run SYS:C/mycli %s", s );
  1549. else
  1550.    {
  1551.    ypos = 136-(mycli_id+1)*16;
  1552.    if ( ypos < 0)
  1553.       ypos = 0;
  1554.    sprintf(work, "run SYS:C/mycli 505 %d 134 64 %d", ypos, mycli_id+1);
  1555.    }
  1556. executive( work );                     /* Execute mycli command */
  1557. }
  1558.  
  1559. #ifdef MODEM
  1560. VOID offline(s)
  1561. UBYTE  *s;
  1562. {
  1563. modem_online = 0;
  1564. }
  1565. #endif
  1566.  
  1567. VOID rename(s)
  1568. UBYTE *s;
  1569. {
  1570. register UBYTE *pc;
  1571.  
  1572. if ( strncmp( s, "from", 4 ) == 0 )          /* remove keyword 'from' */
  1573.    s = stpblk( s + 4 );
  1574.  
  1575. for ( pc = s; *pc && !isspace( *pc ); pc++ )
  1576.    ;
  1577. *pc++ = '\0';
  1578. pc = stpblk( pc );
  1579.  
  1580. if ( strncmp( pc, "as", 2) == 0 || strncmp( pc, "to", 2 ) == 0 )
  1581.    pc = stpblk( pc + 2 );
  1582.  
  1583. if ( !Rename(s, pc) )
  1584.    doserr();
  1585. }
  1586.  
  1587. VOID setcomment(s)
  1588. UBYTE *s;
  1589. {
  1590. register UBYTE *pc;
  1591.  
  1592. for ( pc = s; *pc && !isspace( *pc ); pc++ )
  1593.    ;
  1594. *pc++ = '\0';
  1595. pc = stpblk( pc );
  1596.  
  1597. if ( !SetComment(s, pc) )
  1598.    doserr();
  1599. }
  1600.  
  1601. VOID set(s)
  1602. UBYTE *s;
  1603. {
  1604. register UBYTE  *s2;
  1605.  
  1606. if (      strncmp( s, "path", 4) == 0 )
  1607.    {
  1608.    s2 = path_string;
  1609.    s += 4;
  1610.    }
  1611. else if ( strncmp( s, "chain", 5) == 0 )
  1612.    {
  1613.    s2 = chain_string;
  1614.    s += 5;
  1615.    }
  1616. else if ( strncmp( s, "prompt", 6) == 0 )
  1617.    {
  1618.    s2 = prompt_string;
  1619.    s += 6;
  1620.    }
  1621. else
  1622.    {
  1623.    strcpy( work, "\x1b[33mUndefined system variable\x1b[0m\n" );
  1624.    WriteWork();
  1625.    return;
  1626.    }
  1627.  
  1628. s = stpblk( s );
  1629.  
  1630. if ( *s == '=' )           /* remove keyword '=' */
  1631.    s = stpblk( s + 1 );
  1632.  
  1633. if ( *s == '\0' )
  1634.    {
  1635.    sprintf( work, "%s\n", s2 );
  1636.    WriteWork();
  1637.    }
  1638. else
  1639.    strcpy( s2, s);
  1640. }
  1641.  
  1642. #ifdef MODEM
  1643. VOID TerminalMode(s)
  1644. UBYTE  *s;
  1645. {
  1646. UBYTE buf[74];
  1647.  
  1648.    modem_online = !0;      /* signal that modem is live !!! */
  1649.    if (initialize()) {     /* set baud rate, etc. */
  1650.       Write(mycli_outfp, WelcomeMessage, (long)strlen(WelcomeMessage));
  1651.       while (modem_online) {
  1652.          bdoneflag = 0;    /* terminal mode on flag */
  1653.          Write(mycli_outfp, OnlineMessage, (long)strlen(OnlineMessage));
  1654.          while (!bdoneflag) {
  1655.             check_keyboard();
  1656.             check_modem();
  1657.             }
  1658.          Write(mycli_outfp, OfflineMessage, (long)strlen(OfflineMessage));
  1659.          showprompt();
  1660.          getcommand(buf);
  1661.          CommandInterpreter(buf);
  1662.          }
  1663.       cleanup();
  1664.       }
  1665.    modem_online = 0;
  1666. }
  1667. #endif
  1668.  
  1669. times(s, dss)
  1670. UBYTE *s;
  1671. struct DateStamp *dss;
  1672. {
  1673. register LONG hours,
  1674.               minutes,
  1675.               seconds;
  1676.  
  1677. seconds = dss->ds_Tick / 50L;
  1678. seconds %= 60L;
  1679. minutes = dss->ds_Minute;
  1680. hours = minutes / 60L;
  1681. minutes %= 60L;
  1682. if (hours == 0)
  1683.    hours = 24L;
  1684. sprintf(s, "%2ld:%02ld:%02ld", (hours>12)?hours-12:hours, minutes, seconds);
  1685.  
  1686. if ( hours <= 12 )
  1687.    strcat(s, "a");
  1688. else
  1689.    strcat(s, "p");
  1690. }
  1691.  
  1692. VOID time(s)
  1693. UBYTE *s;
  1694. {
  1695. struct   DateStamp   dss;
  1696.  
  1697. DateStamp(&dss);
  1698. times(work, &dss);
  1699. strcat(work, "\n");
  1700. WriteWork();
  1701. }
  1702.  
  1703. VOID type(s)
  1704. UBYTE *s;
  1705. {
  1706. register struct FileHandle *workfp;
  1707. register WORD i;
  1708. register WORD len2;
  1709. register WORD len;
  1710. register WORD linecount = 1;
  1711. UBYTE         c;
  1712.  
  1713. workfp = Open(s, MODE_OLDFILE);
  1714. if (workfp == 0)
  1715.    {
  1716.    doserr();
  1717.    return;
  1718.    }
  1719. do
  1720.    {
  1721.    len = Read(workfp, work2, 512L);
  1722. #ifdef MODEM
  1723.    if ( !modem_online)
  1724.       {
  1725. #endif
  1726.       len2 = 0;
  1727.       while ( len2 < len)
  1728.          {
  1729.          for ( i=len2; work2[ i ] != '\n' && i < len; i++)
  1730.             ;
  1731.          Write( mycli_outfp, &work2[ len2 ], (long)(i - len2 + 1));
  1732.          len2 = i + 1;
  1733.          if ( moremode)
  1734.             {
  1735.             if (++linecount >= 22 && work2[ i ] == '\n')
  1736.                {
  1737.                linecount = 1;
  1738.                strcpy( work, "\x1b[33mPress <SPACEBAR> for more\x1b[0m");
  1739.                WriteWork();
  1740.                while( (c = scr_csts()) != ' ')
  1741.                   if ( c == BRK || c == ESC)
  1742.                      {
  1743.                      len = 0;
  1744.                      break;
  1745.                      }
  1746.                   else if ( c == '\r')
  1747.                      {
  1748.                      linecount = 21;
  1749.                      break;
  1750.                      }
  1751.                strcpy( work, "\r                         \r");
  1752.                WriteWork();
  1753.                }
  1754.             }
  1755.          else
  1756.             if (!pause())        /* quit the type() by short circuit */
  1757.                len = 0;
  1758.          }
  1759. #ifdef MODEM
  1760.       }
  1761.    else
  1762.       for (len2 = 0; len2 < len; len2++)
  1763.          {
  1764.          Write(mycli_outfp, &work2[ len2 ], 1L);
  1765.          rs_out[ 0 ] = work2[ len2 ];
  1766.          DoIO(ModemWriteRequest);
  1767.          if (!TermEcho)               /* characters will be echoed back */
  1768.             {
  1769.             WaitIO(ModemReadRequest); /* get the echoed character */
  1770.             i = rs_in[ 0 ];
  1771.             BeginIO(ModemReadRequest);
  1772.             }
  1773.          if ( !pause())
  1774.             len = 0;
  1775.          }
  1776. #endif
  1777.    }
  1778. while (len == 512);
  1779. strcpy( work, "\n\x1b[33m*** End of File\x1b[0m\n");
  1780. WriteWork();
  1781. Close(workfp);
  1782. }
  1783.  
  1784. VOID whatis(s)
  1785. UBYTE *s;
  1786. {
  1787. register WORD errorcode;
  1788. register WORD i;
  1789.  
  1790. if ( *s < '0' || *s > '9' )
  1791.    {
  1792.    strcpy( work, "\x1b[33mInvalid errorcode specified\x1b[0m\n");
  1793.    WriteWork();
  1794.    return;
  1795.    }
  1796.  
  1797. errorcode = atoi(s);
  1798. if (errorcode)
  1799.    {
  1800.    for (i=0; errorcodes[ i ].code; i++)
  1801.       if (errorcodes[ i ].code == errorcode)
  1802.          break;
  1803.    if (errorcodes[ i ].code == errorcode)
  1804.       strcpy(work2, errorcodes[ i ].message);
  1805.    else
  1806.       strcpy(work2, "undocumented AmigaDos error code");
  1807.    sprintf( work, "\x1b[33mAmigaDos Error %d: %s\x1b[0m\n", errorcode, work2);
  1808.    WriteWork();
  1809.    }
  1810. }
  1811.  
  1812. #ifdef MODEM
  1813. /*
  1814.  * This function converts an incoming ANSI escape sequence
  1815.  * and processes it.  A buffer is passed where any function
  1816.  * key expansion is to take place.  If the buffer is modified
  1817.  * for any reason, this function returns TRUE.
  1818.  */
  1819. process_event( cmd_line)
  1820. UBYTE *cmd_line;
  1821. {
  1822. WORD  i;
  1823. UBYTE c;
  1824. char event_buffer[ 32 ];
  1825.  
  1826. i = 0;
  1827. while( TRUE ) {
  1828.    Read( mycli_infp, &c, 1L);
  1829.    event_buffer[ i ] = c;
  1830.    if ( c == '~' || c == '|' )
  1831.       break;
  1832.    i++;
  1833.    }
  1834. event_buffer[ i+1 ] = '\0';
  1835. if ( event_buffer[ i ] == '~') {
  1836.    if ( event_buffer[ i ] == '?') {
  1837.       strcpy( cmd_line, "help");
  1838.       return( !0);
  1839.       }
  1840.    else if ( isdigit( event_buffer[ 0 ]) ) {
  1841.       if ( function_key( atoi( event_buffer), cmd_line))
  1842.          return( !0);
  1843.       }
  1844.    }
  1845. return( 0);
  1846. }
  1847.  
  1848. initialize()
  1849. {
  1850. ModemReadRequest = (struct IOExtSer *)AllocMem((long)sizeof(*ModemReadRequest),
  1851.                    MEMF_PUBLIC | MEMF_CLEAR);
  1852. ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
  1853. ModemReadRequest->IOSer.io_Message.mn_ReplyPort = CreatePort("Read_RS", 0L);
  1854.  
  1855. if (OpenDevice(SERIALNAME, 0L, ModemReadRequest, 0L))
  1856.    {
  1857.    strcpy( work, "\x1b[33mCan't open serial read device\x1b[0m\n");
  1858.    WriteWork();
  1859.    DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort);
  1860.    FreeMem(ModemReadRequest, (long)sizeof(*ModemReadRequest));
  1861.    return( 0);
  1862.    }
  1863.  
  1864. ModemReadRequest->IOSer.io_Command = CMD_READ;
  1865. ModemReadRequest->IOSer.io_Length = 1;
  1866. ModemReadRequest->IOSer.io_Data = (APTR) &rs_in[0];
  1867.  
  1868. ModemWriteRequest = (struct IOExtSer *)AllocMem((long)sizeof(*ModemWriteRequest),
  1869.                     MEMF_PUBLIC | MEMF_CLEAR);
  1870. ModemWriteRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
  1871. ModemWriteRequest->IOSer.io_Message.mn_ReplyPort = CreatePort("Write_RS",0L);
  1872.  
  1873. if (OpenDevice(SERIALNAME, 0L, ModemWriteRequest, 0L))
  1874.    {
  1875.    strcpy( work, "\x1b[33mCan't open serial write device\x1b[0m\n");
  1876.    WriteWork();
  1877.    DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort);
  1878.    FreeMem(ModemReadRequest, (long)sizeof(*ModemReadRequest));
  1879.    DeletePort(ModemWriteRequest->IOSer.io_Message.mn_ReplyPort);
  1880.    FreeMem(ModemWriteRequest, (long)sizeof(*ModemWriteRequest));
  1881.    return(0);
  1882.    }
  1883.  
  1884. ModemWriteRequest->IOSer.io_Command = CMD_WRITE;
  1885. ModemWriteRequest->IOSer.io_Length = 1;
  1886. ModemWriteRequest->IOSer.io_Data = (APTR) &rs_out[0];
  1887.  
  1888. /* ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED; */
  1889. ModemReadRequest->io_SerFlags = SERF_SHARED;
  1890. ModemReadRequest->io_Baud = 1200;
  1891. ModemReadRequest->io_ReadLen = 8;
  1892. ModemReadRequest->io_WriteLen = 8;
  1893. ModemReadRequest->io_CtlChar = 13110000L;
  1894. ModemReadRequest->IOSer.io_Command = SDCMD_SETPARAMS;
  1895. DoIO(ModemReadRequest);
  1896.  
  1897. ModemReadRequest->IOSer.io_Command = CMD_READ;
  1898. BeginIO(ModemReadRequest);
  1899. return( !0);
  1900. }
  1901.  
  1902. cleanup()
  1903. {
  1904. CloseDevice( ModemReadRequest);
  1905. DeletePort(  ModemReadRequest->IOSer.io_Message.mn_ReplyPort);
  1906. FreeMem( ModemReadRequest, (long)sizeof(*ModemReadRequest));
  1907.  
  1908. CloseDevice( ModemWriteRequest);
  1909. DeletePort(  ModemWriteRequest->IOSer.io_Message.mn_ReplyPort);
  1910. FreeMem( ModemWriteRequest, (long)sizeof(*ModemWriteRequest));
  1911.  
  1912. Write(mycli_outfp, GoodbyeMessage, (long)strlen(GoodbyeMessage));
  1913. }
  1914.  
  1915. check_keyboard()
  1916. {
  1917. UBYTE *pc;
  1918. UBYTE buf[74];
  1919.  
  1920. if (WaitForChar(mycli_infp, 1L))
  1921.    {
  1922.    Read( mycli_infp, &rs_out[ 0 ], 1L);
  1923.    switch( (UBYTE)rs_out[ 0 ])
  1924.       {
  1925.       case 0x03:                       /* escape to command mode with ^c */
  1926.          bdoneflag = !0;
  1927.          break;
  1928.       case 0x9b:                       /* ANSI keyboard char stuff */
  1929.          if ( process_event(&buf[ 0 ]))  /* send the translation */
  1930.             {
  1931.             pc = &buf[ 0 ];
  1932.             while (*pc != '\0')
  1933.                {
  1934.                rs_out[ 0 ] = *pc++;
  1935.                if ( TermEcho)
  1936.                   Write( mycli_outfp, &rs_out[ 0 ], 1L);
  1937.                DoIO(ModemWriteRequest);
  1938.                check_modem();
  1939.                }
  1940.             rs_out[ 0 ] = '\n';
  1941.             if ( TermEcho)
  1942.                Write( mycli_outfp, &rs_out[0], 1L);
  1943.             DoIO(ModemWriteRequest);
  1944.             rs_out[ 0 ] = '\r';
  1945.             DoIO(ModemWriteRequest);
  1946.             }
  1947.          break;
  1948.       case 0x05:                       /* toggle keystroke echo with ^e */
  1949.          TermEcho = !TermEcho;
  1950.          sprintf( work, "\x1b[33mEcho %s\x1b[0m\n", TermEcho?"ON":"OFF");
  1951.          WriteWork();
  1952.          break;
  1953.       default:
  1954.          if (TermEcho)
  1955.             Write( mycli_outfp, &rs_out[ 0 ], 1L);
  1956.          DoIO( ModemWriteRequest);
  1957.       }
  1958.    }
  1959. }
  1960.  
  1961. /*
  1962.  * Check to see if the Read Request IO has completed from the modem.
  1963.  */
  1964. check_modem()
  1965. {
  1966.  
  1967. if ( CheckIO(ModemReadRequest))
  1968.    {
  1969.    WaitIO( ModemReadRequest);
  1970.    rs_in[ 0 ] &= 0x7f;
  1971.    Write( mycli_outfp, &rs_in[0], 1L);
  1972.    if ( capturing_file)
  1973.       Write( capture_fp, &rs_in[ 0 ], 1L);
  1974.    BeginIO( ModemReadRequest);
  1975.    }
  1976. }
  1977.  
  1978. #endif
  1979.  
  1980. #ifdef AZTEC
  1981. UBYTE *stpblk(str)
  1982. register UBYTE *str;
  1983. {
  1984.    while( *str && isspace(*str) )
  1985.      str++;
  1986.    return ( str );
  1987. }
  1988.  
  1989. isdigit(c)
  1990. register UBYTE c;
  1991. {
  1992. return( (c >= '0') && (c <= '9' ) );   /* depends on ASCII relationships */
  1993.  
  1994. /*  a portable way to do it, but more code
  1995.    switch( c )
  1996.    {
  1997.       case '0': case '1': case '2': case '3': case '4':
  1998.       case '5': case '6': case '7': case '8': case '9':
  1999.          return TRUE;
  2000.    }
  2001.    return FALSE;
  2002. */
  2003.  
  2004. }
  2005.  
  2006. isspace(c)
  2007. register UBYTE c;
  2008. {
  2009.    if ( c == '\t' || c == ' ' || c == '\n' )
  2010.       return TRUE;
  2011.    return FALSE;
  2012. }
  2013. #endif   AZTEC
  2014.  
  2015. #ifdef MOON
  2016. /*
  2017.  *              Phase of the Moon Conversion.
  2018.  *
  2019.  * The phase of the moon (in readable ascii) is written into the buffer,
  2020.  * followed by a null.  The routine returns a pointer to the buffer.
  2021.  *
  2022.  */
  2023. UBYTE moonbuf[22], *phasetxt[] = {
  2024.    "new",
  2025.    "a waxing crescent",
  2026.    "in its first quarter",
  2027.    "waxing gibbous",
  2028.    "full",
  2029.    "waning gibbous",
  2030.    "in its last quarter",
  2031.    "a waning crescent"
  2032. };
  2033.  
  2034. WORD day_year[] = {      /* Days in year for each month */
  2035.    -1, -1, 30, 58, 89, 119, 150, 180, 211, 241, 272, 303, 333
  2036. };                             /* Note: Jan. 1 will equal zero */
  2037.  
  2038. /* Year, 1978 = 1978;  Month, Jan = 1;  Day, 1 = 1
  2039.  *
  2040.  * The algorithm is accurate for the Gregorian calender only.
  2041.  *   
  2042.  * The magic numbers used in the phase calculation are as follows:
  2043.  *  29.5      The moon's period in days.
  2044.  *   177      29.5 scaled by 6
  2045.  *    22      (29.5 / 8) scaled by 6 (this gets the phase)
  2046.  *    11      ((29.5 / 8) / 2) scaled by 6
  2047.  *
  2048.  * Theoretically, this should yield a number in the range 0 .. 7.  However,
  2049.  * two days per year, things don't work out too well.
  2050.  *
  2051.  * Epact is calculated by the algorithm given in Knuth vol. 1 (calculation
  2052.  * of Easter).
  2053.  */
  2054. UBYTE *moon()
  2055. {
  2056. register LONG  cent;            /* Century number (1979 = 20) */
  2057. register LONG  epact;            /* Age of the moon on Jan. 1 */
  2058. register LONG  diy;            /* Day in the year */
  2059. register LONG  golden;            /* Moon's golden number */
  2060. register LONG  phase;            /* Moon phase */
  2061.                                            
  2062.    if (month < 0 || month > 12) month = 0;      /* Just in case */
  2063.    diy = day + day_year[month] + 2;             /* Day in the year */
  2064.    if ( (month > 2) && ((year & 3) == 0) )
  2065.              diy++;                             /* Leapyear fixup */
  2066.    cent = (year / 100) + 1;                     /* Century number */
  2067.    golden = (year % 19) + 1;                    /* Golden number */
  2068.    epact = ((11 * golden) + 20                  /* Golden number */
  2069.       + (((8 * cent) + 5) / 25) - 5             /* 400 year cycle */
  2070.       - (((3 * cent) / 4) - 12)) % 30;          /* Leap year correction */
  2071.    if (epact <= 0)
  2072.       epact += 30;                              /* Age range is 1 .. 30 */
  2073.    if ((epact == 25 && golden > 11) || epact == 24)
  2074.       epact++;
  2075.    phase = (((((diy + epact) * 6) + 11) % 177) / 22) & 7;
  2076.    strcpy(moonbuf,phasetxt[ phase ]);
  2077.    return(moonbuf);
  2078. }
  2079. #endif
  2080.  
  2081.